/**
 * 
 */
package com.fox.webapp.persistent.impl;

import static org.springframework.data.mongodb.core.query.Criteria.where; 
import static org.springframework.data.mongodb.core.query.Update.update; 
import static org.springframework.data.mongodb.core.query.Query.query;
import static org.springframework.data.mongodb.gridfs.GridFsCriteria.whereFilename;

import java.io.InputStream;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.gridfs.GridFsOperations;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.util.StringUtils;

import com.fox.webapp.domain.Person;
import com.fox.webapp.persistent.custom.PersonRepositoryCustom;
import com.mongodb.gridfs.GridFSDBFile;
import com.mongodb.gridfs.GridFSFile;

/**
 * @author yockii
 *
 */
public class PersonRepositoryImpl implements PersonRepositoryCustom {

	@Autowired
	private MongoTemplate mongoTemplate;
	@Autowired
	private GridFsOperations gridFsOperations;

	@Override
	public Person updatePerson(Person p) {
		Query query = new Query(where("id").is(p.getId()));
		Update update = new Update();
		
		update.set("emailVerified", p.getEmailVerified());
		update.set("emailVerifyCode", p.getEmailVerifyCode());
		update.set("mobileVerified", p.getMobileVerified());
		update.set("mobileVerifyCode", p.getMobileVerifyCode());
		update.set("emailModifyCode", p.getEmailModifyCode());
		
		if (StringUtils.hasText(p.getFirstName())) {
			update.set("firstName", p.getFirstName());
		}
		if (StringUtils.hasText(p.getLastName())) {
			update.set("lastName", p.getLastName());
		}
		if(StringUtils.hasText(p.getMobile())){
			update.set("mobile", p.getMobile());
		}
		if(StringUtils.hasText(p.getEmail())){
			update.set("email", p.getEmail());
		}
		if(StringUtils.hasText(p.getSecurityQuestion())){
			update.set("securityQuestion", p.getSecurityQuestion());
		}
		if(StringUtils.hasText(p.getSecurityAnswer())){
			update.set("securityAnswer", p.getSecurityAnswer());
		}
		return mongoTemplate.findAndModify(query, update, FindAndModifyOptions.options().returnNew(true), Person.class);
	}

	@Override
	public Person updatePersonOnlyPassword(Person p) {
		return mongoTemplate.findAndModify(query(where("id").is(p.getId())), update("password", p.getPassword()).set("resetPasswordCode", ""), FindAndModifyOptions.options().returnNew(true), Person.class);
	}

	@Override
	public Person updatePersonOnlyBank(Person p) {
		return mongoTemplate.findAndModify(query(where("id").is(p.getId())), update("bank", p.getBank()), FindAndModifyOptions.options().returnNew(true), Person.class);
	}

	@Override
	public Person updatePersonEmailCode(Person p) {
		return mongoTemplate.findAndModify(query(where("id").is(p.getId())), update("emailVerifyCode", p.getEmailVerifyCode()), FindAndModifyOptions.options().returnNew(true), Person.class);
	}

	@Override
	public int countWithCondition(Person p) {
		Query query = new Query();
		if(StringUtils.hasText(p.getUsername())){
			query.addCriteria(where("username").is(p.getUsername().toLowerCase()));
		}
		if(StringUtils.hasText(p.getEmail())){
			query.addCriteria(where("email").is(p.getEmail().toLowerCase()));
		}
		if(StringUtils.hasText(p.getFirstName())){
			query.addCriteria(where("firstName").regex(p.getFirstName()));
		}
		if(StringUtils.hasText(p.getLastName())){
			query.addCriteria(where("lastName").regex(p.getLastName()));
		}
		if(StringUtils.hasText(p.getMobile())){
			query.addCriteria(where("mobile").regex(p.getMobile()));
		}
		if(StringUtils.hasText(p.getReferenceId())){
			query.addCriteria(where("referenceId").is(p.getReferenceId()));
		}
		return (int) mongoTemplate.count(query, Person.class);
	}

	@Override
	public Page<Person> findPersonByCondition(Person p, Pageable pageRequest) {
		Query query = new Query();
		boolean onlyRef = false;
		boolean other = false;
		if(StringUtils.hasText(p.getUsername())){
			query.addCriteria(where("username").is(p.getUsername().toLowerCase()));
			other = true;
		}
		if(StringUtils.hasText(p.getEmail())){
			query.addCriteria(where("email").is(p.getEmail().toLowerCase()));
			other = true;
		}
		if(StringUtils.hasText(p.getFirstName())){
			query.addCriteria(where("firstName").regex(p.getFirstName()));
			other = true;
		}
		if(StringUtils.hasText(p.getLastName())){
			query.addCriteria(where("lastName").regex(p.getLastName()));
			other = true;
		}
		if(StringUtils.hasText(p.getMobile())){
			query.addCriteria(where("mobile").regex(p.getMobile()));
			other = true;
		}
		if(StringUtils.hasText(p.getReferenceId())){
			query.addCriteria(where("referenceId").is(p.getReferenceId()));
			onlyRef = other?false:true;
		}
		long total = mongoTemplate.count(query, Person.class);
		query.skip(pageRequest.getOffset());
		query.limit(pageRequest.getPageSize());
		if(onlyRef){
			query.fields().include("username").include("registerTime");
		}
		return new PageImpl<Person>(mongoTemplate.find(query, Person.class), pageRequest, total);
	}

	@Override
	public Person updatePersonOnlyLastLoginIp(Person p) {
		Query query = new Query(where("id").is(p.getId()));
		Update update = new Update();
		update.set("lastLoginIp", p.getLastLoginIp());
		return mongoTemplate.findAndModify(query, update, FindAndModifyOptions.options().returnNew(true), Person.class);
	}

	@Override
	public Person addReferCommission(Person p, double money) {
		Query query = new Query(where("id").is(p.getId()));
		Update update = new Update();
		update.inc("totalBalance", money);
		return mongoTemplate.findAndModify(query, update, FindAndModifyOptions.options().returnNew(true), Person.class);
	}

	@Override
	public Person decreaseBalance(Person p, double money) {
		Query query = new Query(where("id").is(p.getId()));
		Update update = new Update();
		update.inc("totalBalance", -money);
		return mongoTemplate.findAndModify(query, update, FindAndModifyOptions.options().returnNew(true), Person.class);
	}

	@Override
	public Person updatePersonOnlyQA(Person p) {
		Query query = new Query(where("id").is(p.getId()));
		Update update = new Update();
		update.set("securityQuestion", p.getSecurityQuestion());
		update.set("securityAnswer", p.getSecurityAnswer());
		return mongoTemplate.findAndModify(query, update, FindAndModifyOptions.options().returnNew(true), Person.class);
	}

	@Override
	public Person updateResetPasswordCode(Person person) {
		Query query = new Query(where("id").is(person.getId()));
		Update update = new Update();
		update.set("resetPasswordCode", person.getResetPasswordCode());
		return mongoTemplate.findAndModify(query, update, FindAndModifyOptions.options().returnNew(true), Person.class);
	}

	@Override
	public Person addCredit(Person person, double credit) {
		Query query = new Query(where("id").is(person.getId()));
		Update update = new Update().inc("credit", credit);
		return mongoTemplate.findAndModify(query, update, FindAndModifyOptions.options().returnNew(true), Person.class);
	}

	@Override
	public Person updateEmailModifyCode(Person person) {
		Query query = new Query(where("id").is(person.getId()));
		Update update = new Update();
		update.set("emailModifyCode", person.getEmailModifyCode());
		return mongoTemplate.findAndModify(query, update, FindAndModifyOptions.options().returnNew(true), Person.class);
	}

	public GridFSFile storeQrcode(InputStream content, Person p){
		return gridFsOperations.store(content, p.getId() + ".png");
	}
	
	public GridFSDBFile getQrcodeFile(Person p){
		return gridFsOperations.findOne(query(whereFilename().is(p.getId()+".png")));
	}

	@Override
	public void updatePersonIpWarning(Person... ps) {
		if(ps == null || ps.length == 0){
			return;
		}
		for (Person p : ps) {
			Query query = new Query(where("id").is(p.getId()));
			Update update = new Update().set("isIpWarning", true);
			mongoTemplate.findAndModify(query, update, Person.class);
		}
	}
}
